//==============================================================================
//
//  File        : mmpf_pwm.c
//  Description : PWM control driver
//  Author      : Ben Lu
//  Revision    : 1.0
//
//==============================================================================
/**
 *  @file mmpf_pwm.c
 *  @brief PWM control driver
 *  @author Ben Lu
 *  @version 1.0
 */
 
#include "config_fw.h"
#include "mmpf_typedef.h"
#include "lib_retina.h"
#include "reg_retina.h"
#include "mmp_err.h"
#include "os_wrap.h"
#include "mmp_reg_gpio.h"
#include "mmpf_pio.h"
#include "mmpf_pwm.h"


#if (SUPPORT_PWM)
extern MMPF_OS_MQID  	HighTask_QId;
extern MMP_BOOL m_bVidRecdPreviewStatus[];
#endif

void MMPF_PWM_ISR(void)
{
#if (SUPPORT_PWM)
   AITPS_AIC pAIC = AITC_BASE_AIC;
   AITPS_PWMB pPWM = (AITPS_PWMB)AITC_BASE_PWM;
   MMP_USHORT pwmstatus[2];
      
   pwmstatus[0] = pPWM->PWM[0].PWM_INT_CPU_EN & pPWM->PWM[0].PWM_INT_CPU_SR;
   pwmstatus[1] = pPWM->PWM[1].PWM_INT_CPU_EN & pPWM->PWM[1].PWM_INT_CPU_SR;

	if(pwmstatus[1] != 0){
		pPWM->PWM[1].PWM_INT_CPU_SR = 0x7;
	   	if(m_bVidRecdPreviewStatus[0] || m_bVidRecdPreviewStatus[1]){
			if(pPWM->PWM[1].PWM_PULSE_A_T3 >=0xFE00){
				RTNA_AIC_IRQ_Dis(pAIC, AIC_SRC_PWM);
			}
		    else{
		    	pPWM->PWM[1].PWM_PULSE_A_T3 += 0x80;	
			}
   		} else { 
			if(pPWM->PWM[1].PWM_PULSE_A_T3 >= 0x7){
				pPWM->PWM[1].PWM_PULSE_A_T3 -= 0x80;	
			}
		    else{
				RTNA_AIC_IRQ_Dis(pAIC, AIC_SRC_PWM);
				pPWM->PWM[1].PWM_CTL = (PWM_PULSE_A_FIRST|PWM_ONE_ROUND|PWM_PULSE_A_NEG|PWM_EN);	
			}
		}
	}
	
	if(pwmstatus[0] != 0){
		pPWM->PWM[0].PWM_INT_CPU_SR = 0x7;   
	} 
#endif
}

MMP_ERR MMPF_PWM_Initialize(void)
{
#if (SUPPORT_PWM)
#if (CHIP == VSN_V2) || (CHIP == VSN_V3)
	AITPS_AIC pAIC = AITC_BASE_AIC;
    AITPS_GBL pGBL = AITC_BASE_GBL;
	static MMP_BOOL ubInitFlag = MMP_FALSE;

	RTNA_WAIT_MS(5);
	if (ubInitFlag == MMP_FALSE) {
		RTNA_AIC_Open(pAIC, AIC_SRC_PWM, pwm_isr_a,
	                   AIC_INT_TO_IRQ | AIC_SRCTYPE_HIGH_LEVEL_SENSITIVE | 7);
	    RTNA_AIC_IRQ_Dis(pAIC, AIC_SRC_PWM);

	    ubInitFlag = MMP_TRUE;
    }

	pGBL->GBL_CLK_DIS1 &= (~GBL_CLK_PWM_DIS);	// Enable PWM clock
	pGBL->GBL_IO_CTL2 |= (GBL_PWM1_2_PB_GPIO11);	// PWM1 => PBGPIO11
	pGBL->GBL_IO_CTL2 |= (GBL_PWM2_2_PB_GPIO13);	// PWM2 => PBGPIO13
	//dbg_printf(0, "GBL_IO_CTL2 = %x\r\n", pGBL->GBL_IO_CTL2);
	
	// Set PBGPIO11 NOT GPIO
	pGBL->GBL_IO_CTL7 &= ~(0x08);
	// Set PBGPIO13 NOT GPIO
	pGBL->GBL_IO_CTL7 &= ~(0x20);
#endif
#endif
    
    #if 0
    {
        //preset for test only 
        //MMPF_PWM_ATTRIBUTE pulseTmp = {MMPF_PWM_ID_2, MMPF_PWM_PULSE_ID_A, 13200, 132000, 132000, 132000, 132000, 0x1};
        //MMPF_PWM_SetAttribe(&pulseTmp);	
    	//MMPF_PWM_ControlSet(MMPF_PWM_ID_2, (PWM_DEFAULT_NEG|PWM_PULSE_A_FIRST|PWM_AUTO_CYC|PWM_PULSE_A_POS|PWM_EN));
        MMPF_PWM_SettingControl(1000, 50);//1kHz, 50%
        MMPF_PWM_SetEnableControl(MMP_TRUE);
    }
    #endif
    
	return MMP_ERR_NONE;
}

MMP_ERR MMPF_PWM_SetAttribe(MMPF_PWM_ATTRIBUTE* uPwmAttribute)
{
	AITPS_PWMB pPWM = (AITPS_PWMB)AITC_BASE_PWM;
	MMP_UBYTE ret = 0xFF;
	//ret = MMPF_OS_AcquireSem(gPWMSemID[uPwmAttribute->uID], PWM_SEM_TIMEOUT);
	if (uPwmAttribute->uPulseID == MMPF_PWM_PULSE_ID_A) {
	    pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_A_CLK_DIV = uPwmAttribute->usClockDiv;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_A_T0 = uPwmAttribute->usClkDuty_T0;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_A_T1 = uPwmAttribute->usClkDuty_T1;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_A_T2 = uPwmAttribute->usClkDuty_T2;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_A_T3 = uPwmAttribute->usClkDuty_T3;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_A_NUM = uPwmAttribute->ubNumOfPulses;
	}
	else if (uPwmAttribute->uPulseID == MMPF_PWM_PULSE_ID_B) {
	    pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_B_CLK_DIV = uPwmAttribute->usClockDiv;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_B_T0 = uPwmAttribute->usClkDuty_T0;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_B_T1 = uPwmAttribute->usClkDuty_T1;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_B_T2 = uPwmAttribute->usClkDuty_T2;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_B_T3 = uPwmAttribute->usClkDuty_T3;
		pPWM->PWM[uPwmAttribute->uID].PWM_PULSE_B_NUM = uPwmAttribute->ubNumOfPulses;
	}
	
	if (ret == 0) {
		//MMPF_OS_ReleaseSem(gPWMSemID[uPwmAttribute->uID]);
	}
	return MMP_ERR_NONE;
}


MMP_ERR MMPF_PWM_EnableInterrupt(MMPF_PWM_ID uID, MMP_BOOL bEnable, PwmCallBackFunc CallBackFunc, MMPF_PWM_INT IntItem)
{
	MMP_UBYTE 	ret = 0xFF;
	AITPS_PWMB 	pPWM = (AITPS_PWMB)AITC_BASE_PWM;
	//ret = MMPF_OS_AcquireSem(gPWMSemID[uID], PWM_SEM_TIMEOUT);
	if (bEnable == MMP_TRUE) {
		//gPwmCallBack[uID] = CallBackFunc;
		pPWM->PWM[uID].PWM_INT_CPU_EN |= (0x1 << IntItem);
	}
	else {
		pPWM->PWM[uID].PWM_INT_CPU_EN &= ~(0x1 << IntItem);
		//gPwmCallBack[uID] = NULL;
	}
	
	if (ret == 0) {
	//	MMPF_OS_ReleaseSem(gPWMSemID[uID]);
	}
	
	return MMP_ERR_NONE;
}

MMP_ERR MMPF_PWM_ControlSet(MMPF_PWM_ID uID, MMP_UBYTE control)
{
#if (SUPPORT_PWM)
#if (CHIP == VSN_V2) || (CHIP == VSN_V3)
	//AITPS_GBL 	pGBL = AITC_BASE_GBL;
	AITPS_AIC 	pAIC = AITC_BASE_AIC;
	AITPS_PWMB 	pPWM = (AITPS_PWMB)AITC_BASE_PWM;
	
	RTNA_AIC_IRQ_En(pAIC, AIC_SRC_PWM);
	pPWM->PWM[uID].PWM_CTL = control;
#endif
#endif
	
	return MMP_ERR_NONE;
}

MMPF_PWM_ATTRIBUTE m_pwm1_setting = 
{MMPF_PWM_ID_1, MMPF_PWM_PULSE_ID_A, 12000, 120000, 120000, 120000, (PWM_BLOCK_CLOCK/1000), 0x1};
MMPF_PWM_ATTRIBUTE m_pwm2_setting = 
{MMPF_PWM_ID_2, MMPF_PWM_PULSE_ID_A, 12000, 120000, 120000, 120000, (PWM_BLOCK_CLOCK/1000), 0x1};

MMP_BOOL gbEnablePWMOutput = MMP_FALSE;
MMP_BOOL gbEnablePWMAutoMode = MMP_FALSE;
MMP_ULONG gbFreqHz = 0; 
MMP_UBYTE gbDuty = 0; 

/** 
@brief Set system PWM auto mode status. 
@param[in] bMode MMP_TRUE is auto mode handled by AIT, MMP_FALSE is manual mode handled by host.  
@retval MMP_ERR_NONE Success.
*/ 
MMP_ERR  MMPF_PWM_SetPWMAutoMode(MMP_BOOL bMode)
{
    gbEnablePWMAutoMode = bMode;
	return MMP_ERR_NONE;
}

/** 
@brief Get system PWM is auto mode or not. 
@param[in] void. 
@retval (MMP_UBYTE) MMP_TRUE is auto mode handled by AIT, MMP_FALSE is manual mode handled by host. 
*/ 
MMP_UBYTE  MMPF_PWM_IsPWMAutoMode(void)
{
    return(gbEnablePWMAutoMode);
}

/** 
@brief Set system PWM output status. 
@param[in] bMode MMP_TRUE is auto mode handled by AIT, MMP_FALSE is manual mode handled by host.  
@retval MMP_ERR_NONE Success.
*/ 
MMP_ERR  MMPF_PWM_SetPWMOutput(MMP_BOOL bMode)
{
    gbEnablePWMOutput = bMode;
	return MMP_ERR_NONE;
}

/**
@brief Set BGPIO13 PWM output enable/disable.
@param[in] bMode 0x00: disable, 0x01: enable, 0x02: auto mode(AIT IQ handle PWM frequency/duty.
@retval MMP_ERR_NONE Success.
*/
MMP_ERR MMPF_PWM_SetEnableControl(MMP_BOOL bMode)
{
#if (SUPPORT_PWM)
    dbg_printf(3," PWM_En %d\r\n",bMode);
    switch(bMode) {
    case 0x00: //PWM_CTL_DISABLE
        MMPF_PWM_ControlSet(MMPF_PWM_ID_1, (PWM_DEFAULT_NEG|PWM_PULSE_A_FIRST|PWM_ONE_ROUND|PWM_PULSE_A_POS|PWM_DIS));
        MMPF_PWM_ControlSet(MMPF_PWM_ID_2, (PWM_DEFAULT_NEG|PWM_PULSE_A_FIRST|PWM_ONE_ROUND|PWM_PULSE_A_POS|PWM_DIS));
        MMPF_PWM_SetPWMOutput(MMP_FALSE);
        break;
    case 0x01: //PWM_CTL_ENABLE
        MMPF_PWM_ControlSet(MMPF_PWM_ID_1, (PWM_PULSE_A_FIRST|PWM_AUTO_CYC|PWM_PULSE_A_POS|PWM_EN));
        MMPF_PWM_ControlSet(MMPF_PWM_ID_2, (PWM_PULSE_A_FIRST|PWM_AUTO_CYC|PWM_PULSE_A_POS|PWM_EN));
        MMPF_PWM_SetPWMOutput(MMP_TRUE);
        break;
    case 0x02: //PWM_CTL_AUTO_MODE
    default:
        //auto mode
    	//MMPF_PWM_ControlSet(MMPF_PWM_ID_2, (PWM_DEFAULT_NEG|PWM_PULSE_A_FIRST|PWM_ONE_ROUND|PWM_PULSE_A_POS|PWM_DIS));
        //MMPF_PWM_SetPWMOutput(MMP_FALSE);
        break;
    }
#endif
	
	return MMP_ERR_NONE;
}

/**
@brief Set BGPIO13 PWM frequency/duty cycle control.
@param[in] pdFreqHz 1~300000 in Hz.
@param[in] pdDuty 0~100 in percentage.
@retval MMP_ERR_NONE Success.
*/
MMP_ERR MMPF_PWM_SettingControl(MMP_ULONG pdFreqHz, MMP_UBYTE pdDuty)
{
#if (SUPPORT_PWM)
    if((pdFreqHz>PWM_FREQ_MAX) || (pdFreqHz<PWM_FREQ_MIN) || (pdDuty>PWM_DUTY_MAX) /*|| (pdDuty<PWM_DUTY_MIN)*/) {
        dbg_printf(3," !ERR, PWM_SettingControl(%d,%d)\r\n",pdFreqHz,pdDuty);
        return MMP_HIF_ERR_PARAMETER;
    }

    gbFreqHz = pdFreqHz;
    gbDuty = pdDuty;
    dbg_printf(3," PWM:F_%d D_%d\r\n",(gbFreqHz),gbDuty);

    m_pwm1_setting.usClkDuty_T0 = ((MMP_ULONG)(PWM_BLOCK_CLOCK/100)*gbDuty)/(gbFreqHz);
    m_pwm1_setting.usClkDuty_T1 = ((MMP_ULONG)(PWM_BLOCK_CLOCK)/(gbFreqHz));
    m_pwm1_setting.usClkDuty_T2 = m_pwm1_setting.usClkDuty_T1;
    m_pwm1_setting.usClkDuty_T3 = m_pwm1_setting.usClkDuty_T1;
    m_pwm1_setting.usClockDiv = (PWM_BLOCK_CLOCK/gbFreqHz);

    MMPF_PWM_SetAttribe(&m_pwm1_setting);
    
    m_pwm2_setting.usClkDuty_T0 = ((MMP_ULONG)(PWM_BLOCK_CLOCK/100)*gbDuty)/(gbFreqHz);
    m_pwm2_setting.usClkDuty_T1 = ((MMP_ULONG)(PWM_BLOCK_CLOCK)/(gbFreqHz));
    m_pwm2_setting.usClkDuty_T2 = m_pwm2_setting.usClkDuty_T1;
    m_pwm2_setting.usClkDuty_T3 = m_pwm2_setting.usClkDuty_T1;
    m_pwm2_setting.usClockDiv = (PWM_BLOCK_CLOCK/gbFreqHz);

    MMPF_PWM_SetAttribe(&m_pwm2_setting);
#endif
	
	return MMP_ERR_NONE;
}